pub mod download;
pub mod response;
pub mod tenant;
pub use download::download_file;
pub use response::ApiResponse;


use argon2::{password_hash::SaltString, Argon2, PasswordHash};
use rand::Rng;
use std::iter;

#[allow(dead_code)]
#[inline]
pub fn random_string(limit: usize) -> String {
    iter::repeat(())
        .map(|_| rand::thread_rng().sample(rand::distributions::Alphanumeric))
        .map(char::from)
        .take(limit)
        .collect()
}

/// Example: generate password hash for "123"
/// let hash = hash_password("123").unwrap();
/// println!("Hash for '123': {}", hash);
pub fn verify_password(password: &str, password_hash: &str) -> anyhow::Result<()> {
    let hash = PasswordHash::new(&password_hash)
        .map_err(|e| anyhow::anyhow!("invalid password hash: {}", e))?;
    let result = hash.verify_password(&[&Argon2::default()], password);
    match result {
        Ok(_) => Ok(()),
        Err(_) => Err(anyhow::anyhow!("invalid password")),
    }
}

pub fn hash_password(password: &str) -> anyhow::Result<String> {
    hash_password_with_salt(password, None)
}

pub fn hash_password_with_salt(password: &str, salt: Option<&str>) -> anyhow::Result<String> {
    let salt = match salt {
        Some(s) => SaltString::from_b64(s)
            .map_err(|e| anyhow::anyhow!("invalid salt: {}", e))?,
        None => SaltString::generate(rand::thread_rng()),
    };
    Ok(PasswordHash::generate(Argon2::default(), password, &salt)
        .map_err(|e| anyhow::anyhow!("failed to generate password hash: {}", e))?
        .to_string())
}

/// Generate password hash for "123" with fixed salt
/// Example output: "$argon2id$v=19$m=4096,t=3,p=1$c2FsdHNhbHRzYWx0$XTu7qZq4XU5qgZ8X4X9X9X9X9X9X9X9X9X9X9X9X9"
#[allow(dead_code)]
pub fn generate_password_123() -> anyhow::Result<String> {
    hash_password_with_salt("123", None) // "saltsaltsalt" in base64
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_password_generation() {
        let hash = generate_password_123().unwrap();
        println!("Hash for '123': {}", hash);
    }
}
